export function parse(template) {
  //状态机
  //上下文: 保存当前操作状态;提供一些函数工具
  const context = {
    source: template,
    advance(num) {
      context.source = context.source.slice(num);
    },
    advanceSpace() {
      const match = /^[\t\r\n\f ]+/.exec(context.source);
      if (match) {
        context.advance(match[0].length);
      }
    },
  };

  return parseChildren(context, []);
}

//const template = "123</span></div>";
function parseChildren(context, stack) {
  // 存储ast结果
  const nodes = [];
  //结束条件
  //stack 判断标签配对
  while (!isEnd(context, stack)) {
    let node;
    if (context.source[0] === "<") {
      //小于号
      //状态2到状态3
      if (context.source[1].match(/[a-z]/i)) {
        node = parseElement(context, stack);
      }
    } else if (context.source.startsWith("{{")) {
      node = parseInterpolation(context)
    }
    //处理text
    if (!node) {
      node = parseText(context);
    }
    nodes.push(node);
  }

  return nodes;
}

function isEnd(context, stack) {
  //字符串被吃完
  if (!context.source) {
    return true;
  }
  //
  const node = stack[stack.length - 1];
  if (node) {
    //配对结束了
    return context.source.startsWith(`</${node.tag}`);
  }
}

function parseElement(context, stack) {
  // 开始标签
  // props
  // children
  const node = parseTag(context);
  if (node.isUnary) {
    return node;
  }
  //const template = "</span></div>";
  stack.push(node);
  node.children = parseChildren(context, stack);
  stack.pop();

  parseTag(context, "end");
  return node;
}

function parseTag(context, type = "start") {
  const startTagReg = /^<([a-z][^\t\r\n\f />]*)/i;
  const endTagReg = /^<\/([a-z][^\t\r\n\f />]*)/i;
  const { advance } = context;
  const pattern = type == "start" ? startTagReg : endTagReg;
  const consumeTag = pattern.exec(context.source);
  //       ></div>
  advance(consumeTag[0].length);
  //自闭和标签/>
  //>
  //解析属性
  const props = parseAttr(context);
  // isUnary: false,
  if (context.source.startsWith("/>")) {
    advance(2);
  } else {
    advance(1);
  }
  return {
    type: "Element",
    tag: consumeTag[1],
    children: [],
    props,
    isUnary: context.source.startsWith("/>") ? true : false, //是否闭合
  };
}

function parseAttr(context) {
  const props = [];
  const { advance, advanceSpace } = context;
  while (context.source.includes("=")) {
    //先吃掉空格
    advanceSpace();
    let key, value;
    const equalIndex = context.source.indexOf("=");
    key = context.source.slice(0, equalIndex);
    advance(key.length);
    //吃掉等号
    advance(1);
    advanceSpace();
    //属性值双引号
    //属性值单引号
    //属性值没有引号
    if (context.source[0] == '"') {
      advance(1);
      const doubleQuota = context.source.indexOf('"');
      value = context.source.slice(0, doubleQuota);
      advance(value.length);
      advance(1);
    } else if (context.source[0] == "'") {
      advance(1);
      const doubleQuota = context.source.indexOf("'");
      value = context.source.slice(0, doubleQuota);
      advance(value.length);
      advance(1);
    } else {
      // const sapceIndex = context.source.indexOf(' ')

      const match = /^[\t\r\n\f ]+/.exec(context.source);
      value = context.source.slice(0, match);
      advance(value.length);
    }
    advanceSpace();
    props.push({
      type: "Attribute",
      name: key,
      value,
    });
  }
  return props;
}

function parseText(context) {
  const { advance, advanceSpace } = context;
  //结束符< | {{
  advanceSpace()
  const textReg = /[a-z0-9\s\u4e00-\u9fa5]+/i;
  const match = textReg.exec(context.source);
  advance(match[0].length);
  return {
    type: "Text",
    content: match[0],
  };
}

function parseInterpolation(context) {
  //吃掉{{
  const { advance, advanceSpace } = context
  advance(2)
  const contextIndex = context.source.indexOf("}}")
  const content = context.source.slice(0, contextIndex)
  advance(content.length)
  //吃掉}}
  advance(2)
  return {
    type: 'Interpolation',
    content: {
      type: 'Expression',
      content
    }
  }
}
